/*
     Copyright 2007 Joseph M. Ferner

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Threading;
using OpenServers.Net.Common.Listener;
using OpenServers.Net.Common.Socket;

namespace OpenServers.Net.Common.State {
    /// <summary>
    /// abstract class to help creating <see cref="IState"/> implementations.
    /// </summary>
    public abstract class AbstractState : IState {
        private readonly byte[] _recieveBuffer = new byte[10 * 1024];
        private readonly ISocket _clientSocket;
        private bool _closeConnection = false;
        private readonly IListener _listener;

        /// <summary>
        /// called when the connection is opened.
        /// </summary>
        public event ConnectionOpenedDelegate ConnectionOpened;

        /// <summary>
        /// called when the connection is closed.
        /// </summary>
        public event ConnectionClosedDelegate ConnectionClosed;

        /// <summary>
        /// called when the state is passed to another thread.
        /// </summary>
        public event AttachThreadDelegate AttachThread;

        /// <summary>
        /// called when the state is about to be removed from a thread.
        /// </summary>
        public event DetachThreadDelgate DetachThread;

        /// <summary>
        /// Called when an error has occured.
        /// </summary>
        public event ErrorDelegate Error;

        /// <summary>
        /// called when data is received on the socket.
        /// </summary>
        public event DataReceivedDelegate DataReceived;

        /// <summary>
        /// fires the ConnectionOpened event.
        /// </summary>
        public void FireConnectionOpened() {
            if (ConnectionOpened != null) {
                ConnectionOpened(this);
            }
        }

        /// <summary>
        /// fires the ConnectionClosed event.
        /// </summary>
        public void FireConnectionClosed() {
            if (ConnectionClosed != null) {
                ConnectionClosed(this);
            }
        }

        /// <summary>
        /// fires the AttachThread event.
        /// </summary>
        public void FireAttachThread(Thread thread) {
            if (AttachThread != null) {
                AttachThread(this, thread);
            }
        }

        /// <summary>
        /// fires the DetachThread event.
        /// </summary>
        public void FireDetachThread(Thread thread) {
            if (DetachThread != null) {
                DetachThread(this, thread);
            }
        }

        /// <summary>
        /// fires the DataReceived event.
        /// </summary>
        public void FireDataReceived(int numberOfBytesReceived) {
            if (DataReceived != null) {
                DataReceived(this, ReceiveBuffer, numberOfBytesReceived);
            }
        }

        /// <summary>
        /// fires the Error event.
        /// </summary>
        public void FireError(Exception ex) {
            if (Error != null) {
                Error(this, ex);
            }
        }

        /// <summary>
        /// constructor.
        /// </summary>
        public AbstractState(IListener listener, ISocket clientSocket) {
            this._clientSocket = clientSocket;
            this._listener = listener;
        }

        /// <summary>
        /// Buffer for use by the receive functions to hold async data.
        /// </summary>
        public byte[] ReceiveBuffer {
            get { return _recieveBuffer; }
        }

        /// <summary>
        /// The client socket.
        /// </summary>
        public ISocket ClientSocket {
            get { return _clientSocket; }
        }

        /// <summary>
        /// flag indicating that the server should close the socket.
        /// </summary>
        public bool CloseConnection {
            get { return _closeConnection; }
            set { _closeConnection = value; }
        }

        /// <summary>
        /// The listener that received this client.
        /// </summary>
        public IListener Listener {
            get { return _listener; }
        }
    }
}
